﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using com.lover.astd.common.model;
using com.lover.astd.common.model.attack;
using com.lover.astd.common.model.battle;
using com.lover.common;

namespace com.lover.astd.common.logic
{
    public class BattleMgr : MgrBase
    {
        private string[] _formations = new string[] { "不变阵", "鱼鳞阵", "长蛇阵", "锋矢阵", "偃月阵", "锥形阵", "八卦阵", "七星阵", "雁行阵" };
        public BattleMgr() { _logColor = System.Drawing.Color.Purple; }

        #region battle info
        public void getWeaponEventInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/server!get51EventTime.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取兵器活动信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results>
            //  <state>1</state>
            //  <message>
            //      <eventbegion>2013-11-09 00:00:00</eventbegion>
            //      <eventend>2013-11-10 00:00:00</eventend>
            //      <effect>75</effect>
            //      <canrecvforcetoken>1</canrecvforcetoken>
            //      <forcetokennum>5</forcetokennum>
            //  </message>
            //</results>
            XmlNode force_token_node = xml.SelectSingleNode("/results/message/canrecvforcetoken");
            if (force_token_node != null) user._battle_got_weapon_event_free_token = force_token_node.InnerText.Equals("0");
            else user._battle_got_weapon_event_free_token = false;

            int forcetoken_num = 0;
            XmlNode forcetoken_num_node = xml.SelectSingleNode("/results/message/forcetokennum");
            if (forcetoken_num_node != null) Int32.TryParse(forcetoken_num_node.InnerText, out forcetoken_num);

            if (!user._battle_got_weapon_event_free_token)
            {
                url = "/root/market!recvForceToken.action";
                result = protocol.getXml(url, "获取兵器活动免费强攻令");
                if (result == null) return;
                if (!result.CmdSucceed)
                {
                    if (result.CmdError.Contains("已领取")) { user._battle_got_weapon_event_free_token = true; return; }
                }
                xml = result.CmdResult;
                //<results><state>1</state><message></message></results>
                logInfo(logger, String.Format("领取兵器活动免费强攻令[{0}]个", forcetoken_num));
                user._battle_got_weapon_event_free_token = true;
            }
        }
        public void getBattleInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/battle.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取战争信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            XmlNode free_force_attack_node = xml.SelectSingleNode("/results/freeattnum");
            if (free_force_attack_node != null) Int32.TryParse(free_force_attack_node.InnerText, out user._battle_free_force_token);
            else user._battle_free_force_token = 0;
        }

        public int tryFindArmy(ProtocolMgr protocol, ILogger logger, User user, string armyid, bool onlyFirstBattle)
        {
            string url = "/root/multiBattle!getTeamInfo.action";
            string data = "armiesId=" + armyid;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "获取军团征战信息");
            if (result == null || !result.CmdSucceed) return 1;
            XmlDocument xml = result.CmdResult;
            string armyname = xml.SelectSingleNode("/results/armies/name").InnerText;
            XmlNode current_num = xml.SelectSingleNode("/results/currentnum");
            if (current_num != null) // 已经加入了该军团的队伍
            {
                user._battle_current_army_id = armyid;
                return 0;
            }
            string desc = "";
            XmlNode scene = xml.SelectSingleNode("/results/sceneevent");
            if (scene != null) // 军团战已打完
            {
                string describe = "", gains = "";
                XmlNode desc_node = scene.SelectSingleNode("battlereport/report/describe");
                if (desc_node != null) describe = desc_node.InnerText;
                XmlNode gain_node = scene.SelectSingleNode("battlereport/report/gains");
                if (gain_node != null) gains = gain_node.InnerText;
                if (gains != "")
                {
                    //string[] res = translateGainItem(gains);
                    //if(res != null && res.Length > 0) gains = "获得" + res[0];
                }
                desc = String.Format("攻打{0}, {1}, {2}", armyname, describe, gains);
                logInfo(logger, desc);
                user._battle_current_army_id = "";
                desc = "";
                XmlNode battleinfo_node = scene.SelectSingleNode("playerbattleinfo");
                if (battleinfo_node != null)
                {
                    user.refreshPlayerInfo(battleinfo_node);
                    user.addUiToQueue(ConfigStrings.S_Global);
                }
            }

            XmlNode results = xml.SelectSingleNode("/results");
            XmlNodeList childs = results.ChildNodes;
            string nation = user.Nation;
            string group = user.Group;
            int level = user.Level;
            int join_result = -1;
            foreach (XmlNode child in childs)
            {
                if (child.Name == "team")
                {
                    XmlNodeList child_nodes = child.ChildNodes;
                    string teamid = "", teamname = "", condition = ""; int nowcount = 0, maxcount = 0, firstbattle = 0;
                    foreach (XmlNode cnode in child_nodes)
                    {
                        if (cnode.Name == "teamid") teamid = cnode.InnerText;
                        else if (cnode.Name == "teamname") teamname = cnode.InnerText;
                        else if (cnode.Name == "maxnum") maxcount = Int32.Parse(cnode.InnerText);
                        else if (cnode.Name == "currentnum") nowcount = Int32.Parse(cnode.InnerText);
                        else if (cnode.Name == "condition") condition = cnode.InnerText;
                        else if (cnode.Name == "firstbattle") firstbattle = Int32.Parse(cnode.InnerText);
                    }

                    if (teamid == "" || maxcount == nowcount) continue;
                    // 判断condition
                    // 如果只要首次, 检查首次
                    if (onlyFirstBattle && firstbattle == 0) continue;

                    //if(condition.IndexOf(nation) < 0) continue;  // 国别已经不区分了, 所以这条不要了
                    if (condition.IndexOf("军团") >= 0 && condition.IndexOf(group) < 0) continue; // 军团
                    if (getArmyJoinLevel(condition) > level) continue; // 级别
                    join_result = tryJoinTeam(protocol, logger, teamid, armyname, teamname);
                    if (join_result >= 0)
                    {
                        if (join_result == 0) user._battle_current_army_id = armyid;
                        return join_result;
                    }
                }
            }
            return join_result;
        }
        public int tryJoinTeam(ProtocolMgr protocol, ILogger logger, string teamid, string armyname, string teamname)
        {
            string url = "/root/multiBattle!joinTeam.action";
            string data = "teamId=" + teamid;
            string desc = String.Format("攻打[ {0} ], 加入[ {1} ]队伍", armyname, teamname);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, desc);
            if (result == null) return 1;
            if (!result.CmdSucceed)
            {
                string err = result.CmdError;
                if (err == null) return 1;
                if (err.IndexOf("军令还没有冷却") >= 0) return 2;
                else if (err.IndexOf("没有可用的军令") >= 0) return 3;
                else if (err.IndexOf("满") >= 0) return -1;
                else return 5;
            }
            XmlDocument xml = result.CmdResult;
            logInfo(logger, desc);
            return 0;
        }
        /// <summary>
        /// returns, 0=success, 1=http failure, 2=cd, 3=no order, 4=unknown
        /// </summary>
        /// <param name="npcid"></param>
        /// <returns></returns>
        public int attackNpc(ProtocolMgr protocol, ILogger logger, User user, string npcid, bool force, string formation)
        {
            string url = "/root/battle!battleArmy.action";
            if (force) url = "/root/battle!forceBattleArmy.action";
            string data = "armyId=" + npcid;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "攻打Npc");
            if (result == null) return 1;
            if (!result.CmdSucceed)
            {
                if (result.CmdError.IndexOf("还没有冷却") >= 0) return 2;
                else return 3;
            }
            XmlDocument xml = result.CmdResult;

            XmlNode cdinfo = xml.SelectSingleNode("/results/playerbattleinfo");
            if (cdinfo != null)
            {
                user.refreshPlayerInfo(cdinfo);
                user.addUiToQueue(ConfigStrings.S_Global);
            }

            XmlNode results = xml.SelectSingleNode("/results/battlereport");
            XmlNodeList childs = results.ChildNodes;
            string youlost = "", enemylost = "", message = "";
            foreach (XmlNode child in childs)
            {
                if (child.Name == "attlost") youlost = child.InnerText;
                else if (child.Name == "deflost") enemylost = child.InnerText;
                else if (child.Name == "message") message = child.InnerText;
            }
            string desc = String.Format("{0}NPC, {1}, 你损失兵力{2}, 敌方损失兵力{3} ", force ? "强征" : "征战", message, youlost, enemylost);
            XmlNode items = xml.SelectSingleNode("/results/items/list");
            if (items.HasChildNodes)
            {
                XmlNodeList item_nodes = items.ChildNodes;
                desc += ", 获得";
                user._battle_extra_npc_id = 0;
                user._battle_extra_npc_remains = 0;
                foreach (XmlNode inode in item_nodes)
                {
                    if (inode.Name == "value")
                    {
                        string[] res = translateGainItem(inode.InnerText);
                        string itemname = res[0], itemcolor = res[1];
                        if (itemname == null || itemname == "") itemname = inode.InnerText;
                        if (itemname.IndexOf("battleevent") >= 0)
                        {
                            //battleevent:10:0:1
                            string[] values = itemname.Split(':');
                            if (values.Length >= 4)
                            {
                                string remain = values[1];
                                string extra = values[2];
                                string nothing_count = values[3];
                                desc += String.Format("[征战事件: 还剩[{0}]次, 本次额外获得碎片[{1}]个]", remain, extra);
                                Int32.TryParse(remain, out user._battle_extra_npc_remains);
                            }
                        }
                        else
                        {
                            desc += itemname + "  ";
                        }
                    }
                }
                if (user._battle_extra_npc_remains > 0)
                {
                    Int32.TryParse(npcid, out  user._battle_extra_npc_id);
                    user._battle_extra_npc_formation = formation;
                }
            }
            logInfo(logger, desc);
            return 0;
        }
        public string getFormation(ProtocolMgr protocol, ILogger logger)
        {
            string defaultFormation = _formations[0];
            string url = "/root/general!formation.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取阵型");
            if (result == null || !result.CmdSucceed) return defaultFormation;
            if (!result.CmdSucceed) return defaultFormation;
            XmlDocument xml = result.CmdResult;
            XmlNode node = xml.SelectSingleNode("/results/formation/formationid");
            if (node == null) return defaultFormation;
            int formationid = 0;
            Int32.TryParse(node.InnerText, out formationid);
            if (formationid == 0) return defaultFormation;
            formationid = (int)(formationid / 20);
            if (formationid > _formations.Length) return defaultFormation;
            return _formations[formationid];
        }
        public bool changeFormation(ProtocolMgr protocol, ILogger logger, string formation)
        {
            string url = "/root/general!saveDefaultFormation.action";
            int formationid = 0;
            for (int i = 0, len = _formations.Length; i < len; i++)
            {
                if (_formations[i].Equals(formation))
                {
                    formationid = i;
                    break;
                }
            }
            if (formationid == 0) return true;
            formationid = formationid * 20;
            string data = "formationId=" + formationid;
            string desc = "变换阵型为" + formation;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, desc);
            if (result == null || !result.CmdSucceed) return false;
            //<results><state>1</state><message>更换阵型成功</message></results>
            logInfo(logger, desc);
            return true;
        }

        public List<int> getAllPowerInfo(ProtocolMgr protocol, ILogger logger, User user, List<int> powerids)
        {
            List<int> next = new List<int>();
            if (powerids.Count == 0) return next;
            for (int i = 0, len = powerids.Count, j = 0, len_j = 0; i < len; i++)
            {
                List<int> n = getPowerInfo(protocol, logger, user, powerids[i]);
                for (j = 0, len_j = n.Count; j < len_j; j++) if (!next.Contains(n[j])) next.Add(n[j]);
            }
            if (next.Count == 0) return next;
            else return getAllPowerInfo(protocol, logger, user, next);
        }
        private List<int> getPowerInfo(ProtocolMgr protocol, ILogger logger, User user, int powerId)
        {
            List<int> nextpowers = new List<int>();
            string url = "/root/battle!getPowerInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, "powerId=" + powerId, "获取征战信息");
            if (result == null || !result.CmdSucceed) return nextpowers;
            XmlDocument xml = result.CmdResult;
            XmlNode results = xml.SelectSingleNode("/results");
            XmlNodeList childs = results.ChildNodes;
            string powername = "";
            foreach (XmlNode child in childs)
            {
                if (child.Name == "army")
                {
                    XmlNodeList army_nodes = child.ChildNodes;
                    int armid = 0, armtype = 0, attackable = 0; string armname = "", armitem = "", armitemcolor = "";
                    foreach (XmlNode armynode in army_nodes)
                    {
                        if (armynode.Name == "armyid") armid = Int32.Parse(armynode.InnerText);
                        else if (armynode.Name == "armyname") armname = armynode.InnerText;
                        else if (armynode.Name == "itemname")
                        {
                            string[] res = translateItem(armynode.InnerText);
                            armitem = res[0]; armitemcolor = res[1];
                        }
                        else if (armynode.Name == "type") armtype = Int32.Parse(armynode.InnerText);
                        else if (armynode.Name == "attackable") attackable = Int32.Parse(armynode.InnerText);
                    }
                    if (attackable != 0)
                    {
                        if ((armitem == "" && armtype == 5) || armitem != "")
                        {
                            Npc npc = new Npc(); npc.Id = armid;
                            npc.ItemName = armitem;
                            npc.Name = String.Format("{0}({1})", armname, powername);
                            npc.Type = armtype; npc.ItemColor = armitemcolor;

                            if (npc.Type == 5) addArmies(user, npc);
                            else addNpcs(user, npc);
                        }
                    }
                }
                else if (child.Name == "power")
                {
                    XmlNode nameNode = child.SelectSingleNode("powername");
                    if (nameNode != null) powername = nameNode.InnerText;
                    XmlNode powernode = child.SelectSingleNode("nextpower");
                    if (powernode != null && powernode.HasChildNodes)
                    {
                        XmlNodeList power_nodes = powernode.ChildNodes;
                        int pid = 0, attackable = 0;
                        foreach (XmlNode pnode in power_nodes)
                        {
                            if (!pnode.HasChildNodes) continue;
                            pid = 0; attackable = 0;
                            foreach (XmlNode pchildnode in pnode.ChildNodes)
                            {
                                if (pchildnode.Name == "powerid") pid = Int32.Parse(pchildnode.InnerText);
                                else if (pchildnode.Name == "attackable") attackable = Int32.Parse(pchildnode.InnerText);
                            }
                            if (attackable == 1) nextpowers.Add(pid);
                        }
                    }
                }
            }
            return nextpowers;
        }
        private void addArmies(User user, Npc army)
        {
            bool found = false;
            for (int i = 0, len = user._all_armys.Count; i < len; i++)
            {
                if (user._all_armys[i].Id == army.Id)
                {
                    found = true; break;
                }
            }
            if (!found)
            {
                if (user._battle_max_army_id < army.Id) user._battle_max_army_id = army.Id;
                user._all_armys.Insert(0, army);
            }
        }
        private void addNpcs(User user, Npc npc)
        {
            bool found = false;
            for (int i = 0, len = user._all_npcs.Count; i < len; i++)
            {
                if (user._all_npcs[i].Id == npc.Id)
                {
                    found = true; break;
                }
            }
            if (!found) user._all_npcs.Insert(0, npc);
        }
        private string[] translateItem(string rawtext)
        {
            string[] names = new string[2];
            Regex reg_name = new Regex(@"(#\w{6})'>(.+)</font>(.+)");
            Match match = reg_name.Match(rawtext);
            GroupCollection groups = match.Groups;
            names[1] = groups[1].Value;
            names[0] = groups[2].Value + groups[3].Value;
            return names;
        }
        private string[] translateGainItem(string rawtext)
        {
            string[] names = new string[2];
            if (rawtext == null || rawtext == "") return names;
            rawtext = rawtext.Replace("\r", "").Replace("\n", "");
            Regex reg_name = new Regex(@"([^<]*?).*?(#\w{6})'>(.+)</font>");
            Match match = reg_name.Match(rawtext);
            GroupCollection groups = match.Groups;
            names[1] = groups[2].Value;
            names[0] = groups[3].Value;
            return names;
        }
        private int getArmyJoinLevel(string rawtext)
        {
            Regex reg_level = new Regex(@".*(\d+)级.*");
            Match match = reg_level.Match(rawtext);
            GroupCollection groups = match.Groups;
            return Int32.Parse(groups[1].Value);
        }
        #endregion

        #region attack player info
        public void getNewAreaInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/world!getNewArea.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界世界界面");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;

            XmlNode transfercd_node = xml.SelectSingleNode("/results/tranfercd");
            if (transfercd_node != null) Int32.TryParse(transfercd_node.InnerText, out user._attack_transfer_cd);
            else user._attack_transfer_cd = 0;

            XmlNode score_node = xml.SelectSingleNode("/results/battlescore");
            if (score_node != null) Int32.TryParse(score_node.InnerText, out user._attack_battleScore);

            XmlNodeList area_nodes = xml.SelectNodes("/results/newarea");
            user._attack_all_areas.Clear();
            foreach (XmlNode area_node in area_nodes)
            {
                XmlNodeList child_nodes = area_node.ChildNodes;
                AreaInfo area = new AreaInfo();
                foreach (XmlNode child in child_nodes)
                {
                    if (child.Name == "areaid") area.areaid = Int32.Parse(child.InnerText);
                    else if (child.Name == "nation") area.nation = Int32.Parse(child.InnerText);
                    else if (child.Name == "areaname") area.areaname = child.InnerText;
                    else if (child.Name == "transferable") area.transferable = child.InnerText == "1";
                    else if (child.Name == "enterable") area.enterable = child.InnerText == "1";
                    else if (child.Name == "isselfarea") area.isselfarea = child.InnerText == "1";
                    else if (child.Name == "scopecount") area.scopecount = Int32.Parse(child.InnerText);
                }
                if (area.isselfarea)
                {
                    user._attack_selfCityId = area.areaid;
                }
                if (area.areaid > 0)
                {
                    user.setNewAreaCityNation(area.areaid, area.nation);
                    user._attack_all_areas.Add(area);
                }
            }
        }

        #region battle score
        public void getBattleScoreInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/world!getBattleRankingInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界战绩界面");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;

            XmlNode score_node = xml.SelectSingleNode("/results/score");
            if (score_node != null) Int32.TryParse(score_node.InnerText, out user._attack_battleScore);

            XmlNodeList reward_nodes = xml.SelectNodes("/results/scorerewardinfo/rinfo");
            foreach (XmlNode reward_node in reward_nodes)
            {
                XmlNodeList child_nodes = reward_node.ChildNodes;
                bool can_get = false, already_got = false; int pos = 0;
                foreach (XmlNode child in child_nodes)
                {
                    if (child.Name == "id") pos = Int32.Parse(child.InnerText);
                    else if (child.Name == "get") already_got = child.InnerText == "1";
                    else if (child.Name == "canget") can_get = child.InnerText == "1";
                }
                if (can_get)
                {
                    if (already_got) user._attack_battleScore_awardGot[pos - 1] = 2;
                    else user._attack_battleScore_awardGot[pos - 1] = 1;
                }
                else
                {
                    user._attack_battleScore_awardGot[pos - 1] = 0;
                }
            }
        }
        public void getBattleScoreAward(ProtocolMgr protocol, ILogger logger, int position)
        {
            string url = "/root/world!getBattleScoreReward.action";
            string data = "pos=" + position;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "新世界获取战绩宝箱");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            // <results><state>1</state><baoshi>50</baoshi></results>
            int gemcount = 0;
            XmlNode gem_node = xml.SelectSingleNode("/results/baoshi");
            if (gem_node != null) Int32.TryParse(gem_node.InnerText, out gemcount);
            logInfo(logger, String.Format("领取战绩奖励, 宝石+{0}", gemcount));
        }
        #endregion

        #region user token
        public void getUserTokens(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/world!getNewAreaToken.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界获取个人令");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            user._attack_user_tokens.Clear();
            XmlNodeList token_nodes = xml.SelectNodes("/results/tokenlist");
            foreach (XmlNode token_node in token_nodes)
            {
                UserToken tok = new UserToken();
                XmlNodeList child_nodes = token_node.ChildNodes;
                foreach (XmlNode child in child_nodes)
                {
                    if (child.Name == "id") tok.id = Int32.Parse(child.InnerText);
                    else if (child.Name == "tokenid") tok.tokenid = Int32.Parse(child.InnerText);
                    else if (child.Name == "name") tok.name = child.InnerText;
                    else if (child.Name == "level") tok.level = Int32.Parse(child.InnerText);
                }
                user._attack_user_tokens.Add(tok);
            }
            // city event
            XmlNode cityevent_reward_node = xml.SelectSingleNode("/results/playercityevent/canreward");
            if (cityevent_reward_node != null) Int32.TryParse(cityevent_reward_node.InnerText, out user._attack_can_reward_cityevent);
            else user._attack_can_reward_cityevent = 0;

            XmlNode cityevent_num_node = xml.SelectSingleNode("/results/playercityevent/remaintimes");
            if (cityevent_num_node != null) Int32.TryParse(cityevent_num_node.InnerText, out user._attack_remain_cityevent_num);
            else user._attack_remain_cityevent_num = 0;

            XmlNode city_event_name_node = xml.SelectSingleNode("/results/playercityevent/cityevent/name");
            if (city_event_name_node != null) user._attack_current_cityevent_name = city_event_name_node.InnerText;

            XmlNode city_event_cdtime_node = xml.SelectSingleNode("/results/playercityevent/cdtime");
            if (city_event_cdtime_node != null) Int32.TryParse(city_event_cdtime_node.InnerText, out user._attack_current_cityevent_cdtime);
        }
        private bool useInspireToken(ProtocolMgr protocol, ILogger logger, int newTokenId)
        {
            string url = "/root/world!useInspireToken.action";
            string data = "newTokenId=" + newTokenId;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "使用鼓舞令");
            if (result == null || !result.CmdSucceed) return false;
            //<results><state>1</state><tokenlevel>1</tokenlevel><effect>5.0</effect></results>
            XmlDocument xml = result.CmdResult;

            int tokenLevel = 0;
            XmlNode level_node = xml.SelectSingleNode("/results/tokenlevel");
            if (level_node != null) Int32.TryParse(level_node.InnerText, out tokenLevel);

            float tokenEffect = 0;
            XmlNode effect_node = xml.SelectSingleNode("/results/effect");
            if (effect_node != null) float.TryParse(effect_node.InnerText, out tokenEffect);

            logInfo(logger, String.Format("使用[{0}级鼓舞令], 成功, 攻防+{1}%, 持续24小时", tokenLevel, tokenEffect));
            return true;
        }
        private bool useConstructToken(ProtocolMgr protocol, ILogger logger, int newTokenId)
        {
            string url = "/root/world!useConstuctToken.action";
            string data = "newTokenId=" + newTokenId;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "使用建造令");
            if (result == null || !result.CmdSucceed) return false;

            XmlDocument xml = result.CmdResult;

            int tokenLevel = 0;
            XmlNode level_node = xml.SelectSingleNode("/results/tokenlevel");
            if (level_node != null) Int32.TryParse(level_node.InnerText, out tokenLevel);

            float tokenEffect = 0;
            XmlNode effect_node = xml.SelectSingleNode("/results/effect");
            if (effect_node != null) float.TryParse(effect_node.InnerText, out tokenEffect);

            logInfo(logger, String.Format("使用[{0}级建造令], 成功, 城防+{1}", tokenLevel, tokenEffect));
            return true;
        }
        private bool useScoreToken(ProtocolMgr protocol, ILogger logger, int newTokenId)
        {
            string url = "/root/world!useScoreToken.action";
            string data = "newTokenId=" + newTokenId;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "使用战绩令");
            if (result == null || !result.CmdSucceed) return false;
            logInfo(logger, "使用战绩令");
            return true;
        }
        public void useToken(ProtocolMgr protocol, ILogger logger, User user, int target_min_battle_score)
        {
            if (user._attack_user_tokens == null || user._attack_user_tokens.Count == 0) return;
            foreach (UserToken tok in user._attack_user_tokens)
            {
                bool use_or_not = false;
                if (tok.tokenid == 1) // 建造令
                {
                    if (user._attack_maxCityHp - user._attack_cityHp > 50) useConstructToken(protocol, logger, tok.id);
                }
                else if (tok.tokenid == 4) // 鼓舞令
                {
                    if (user._attack_inspiredState == 0) use_or_not = true;
                    else
                    {
                        if (user._attack_inspiredEffect <= tok.level) use_or_not = true;
                    }
                    if (use_or_not) useInspireToken(protocol, logger, tok.id);
                }
                else if (tok.tokenid == 8) // 战绩令
                {
                    // 需要首先判断是否现在已经用了战绩令了
                    // 必须是城市不在恢复城防, 并且攻击没有cd, 并且攻击cd<10分钟, 才使用战绩令
                    if (user._attack_cityHpRecoverCd == 0 && !user.TokenCdFlag && user.TokenCdTime < 10 * 60 * 1000 && user._attack_battleScore < target_min_battle_score)
                        useScoreToken(protocol, logger, tok.id);
                }
            }
        }
        #endregion

        #region move area

        public AreaInfo getNextMoveArea(ProtocolMgr protocol, ILogger logger, User user, string target_cityname)
        {
            // 简单起见, 如果没有设置, 那么每个国家沿着一条固定路线行进,
            // 魏国: 许都(112)->南阳(111)->博望(110)->房龄(109)->剑阁(108)->西平关(107)
            // 蜀国: 成都(113)->南郑(114)->当阳(115)->华容(116)->隆中(117)->小沛(118)
            // 吴国: 武昌(134)->衡阳(133)->零陵(132)->苍梧(131)->涪陵(125)->白帝城(119)
            // 如果玩家不在这3条线上, 则会将玩家拉到这3条线上来

            if (user._attack_nation_battle_city != null && user._attack_nation_battle_city.Length > 0)
            {
                logInfo(logger, String.Format("目前处于攻坚战集结期间, 集结目标为[{0}], 将忽略设置的移动目标", user._attack_nation_battle_city));
                target_cityname = user._attack_nation_battle_city;
            }
            AreaInfo target_area = user.getAreaByName(target_cityname);
            int target_cityid = 0;
            if(target_area != null) target_cityid = target_area.areaid;
            int self_nation = user.NationInt;
            if (target_cityid == 0)
            {
                if (self_nation == 1) target_cityid = 108;
                else if (self_nation == 2) target_cityid = 117;
                else if (self_nation == 3) target_cityid = 125;
            }
            if (user._attack_selfCityId == target_cityid) return null;
            if (target_area == null) target_area = user.getAreaById(target_cityid);

            AreaInfo _selfArea = user.getAreaById(user._attack_selfCityId);
            List<AreaInfo> path_to_target = findAttackPath(user, user._attack_selfCityId, target_cityid);
            if (path_to_target.Count == 0)
            {
                logInfo(logger, String.Format("设定移动目标为[{0}], 该目标从当前城市无法到达, 重新计算最近城市", target_cityname));
                int counter = 0;
                // 首先判断用户当前在地图的第几行和第几列
                int row_index = (_selfArea.areaid - 101) / 6, column_index = (_selfArea.areaid - 101) % 6;
                // 再看目标在当前地图的第几行和第几列
                int target_row_index = (target_cityid - 101) / 6, target_column_index = (target_cityid - 101) % 6;

                bool self_to_target_row_positive = row_index < target_row_index;
                bool self_to_target_column_positive = column_index < target_column_index;

                int cur_target_row = target_row_index, cur_target_column = target_column_index;
                while (path_to_target.Count == 0 && counter < 20) // 如果20次都还没有找到路径, 那么放弃, 奇数动row,偶数动column
                {
                    if (cur_target_row == row_index && cur_target_column == column_index) break;
                    // 查找其他城市
                    if (counter % 2 == 1)
                    {
                        if (cur_target_row != row_index)
                        {
                            if (self_to_target_row_positive) cur_target_row--;
                            else cur_target_row++;
                        }
                        else
                        {
                            if (self_to_target_column_positive) cur_target_column--;
                            else cur_target_column++;
                        }
                    }
                    else
                    {
                        if (cur_target_column != column_index)
                        {
                            if (self_to_target_column_positive) cur_target_column--;
                            else cur_target_column++;
                        }
                        else
                        {
                            if (self_to_target_row_positive) cur_target_row--;
                            else cur_target_row++;
                        }
                    }
                    counter++;
                    int tmp_aid = 101 + cur_target_row * 6 + cur_target_column;
                    path_to_target = findAttackPath(user, _selfArea.areaid, tmp_aid);
                    if (path_to_target.Count > 0)
                    {
                        target_area = user.getAreaById(tmp_aid);
                        break;
                    }
                }
                if (path_to_target.Count > 0)
                {
                    logInfo(logger, String.Format("重新计算移动城市为[{0}], 开始计算路径", target_area.areaname));
                }
            }

            if (path_to_target.Count > 0)
            {
                AreaInfo next_area = null;
                string desc = String.Format("移动目标为[{0}],当前在[{1}], 途经城市: ", target_area.areaname, _selfArea.areaname);
                if (target_area.areaid == _selfArea.areaid)
                {
                    next_area = null;
                    desc = String.Format("移动目标为[{0}], 当前已在该城市, 不移动", _selfArea.areaname);
                }
                else
                {
                    foreach (AreaInfo area in path_to_target)
                    {
                        if (area.areaid == _selfArea.areaid || area.areaid == target_area.areaid) continue;
                        if (next_area == null) next_area = area;
                        desc += String.Format("[{0}],", area.areaname);
                    }
                    if (next_area == null) next_area = target_area;
                    if (next_area.areaid == _selfArea.areaid)
                    {
                        next_area = null;
                        desc = String.Format("移动目标为[{0}], 当前已在该城市, 不移动", _selfArea.areaname);
                    }
                }

                logInfo(logger, desc);
                return next_area;
            }
            return null;
        }
        public List<AreaInfo> findAttackPath(User user, int selfAreaId, int targetAreaId)
        {
            List<AreaInfo> areas = new List<AreaInfo>();
            // 首先判断用户当前在地图的第几行和第几列
            int row_index = (selfAreaId - 101) / 6, column_index = (selfAreaId - 101) % 6;
            // 再看目标在当前地图的第几行和第几列
            int target_row_index = (targetAreaId - 101) / 6, target_column_index = (targetAreaId - 101) % 6;
            int[,] area_matrix = new int[6, 6];
            for (int i = 0; i < 6; i++)
                for (int j = 0; j < 6; j++)
                    area_matrix[i, j] = -1;
            int self_nation = user.NationInt;
            foreach (AreaInfo area in user._attack_all_areas)
            {
                int aid = area.areaid;
                if (aid == 112 || aid == 113 || aid == 134) continue;// 如果是国家主城, 那么不可进入
                int tmp_row = (aid - 101) / 6;
                int tmp_column = (aid - 101) % 6;
                if (area.nation == self_nation || area.nation == 0) area_matrix[tmp_row, tmp_column] = 1;
                else area_matrix[tmp_row, tmp_column] = -1;
            }
            List<Point> path = CommonUtils.getAStarPath(area_matrix,
                new Point(row_index, column_index), new Point(target_row_index, target_column_index));
            foreach (Point p in path)
            {
                int aid = 101 + p.X * 6 + p.Y;
                AreaInfo area = user.getAreaById(aid);
                if (area != null) areas.Add(area);
            }
            return areas;
        }
        public List<AreaInfo> getNearAreas(User user)
        {
            int self_areaid = user._attack_selfCityId;
            List<AreaInfo> infos = new List<AreaInfo>();
            int area_up_id = self_areaid - 6;
            int area_down_id = self_areaid + 6;
            int area_left_id = self_areaid - 1;
            int area_right_id = self_areaid + 1;
            if ((self_areaid - 100) % 6 == 0 || self_areaid == 105) // 最右边
            {
                area_right_id = 0;
            }
            else if ((self_areaid - 100) % 6 == 1 || self_areaid == 102) // 最左边
            {
                area_left_id = 0;
            }
            // 如果是国家主城, 那么忽略不计
            if (area_up_id == 112 || area_up_id == 113 || area_up_id == 134) area_up_id = 0;
            if (area_down_id == 112 || area_down_id == 113 || area_down_id == 134) area_down_id = 0;
            if (area_left_id == 112 || area_left_id == 113 || area_left_id == 134) area_left_id = 0;
            if (area_right_id == 112 || area_right_id == 113 || area_right_id == 134) area_right_id = 0;

            AreaInfo area = user.getAreaById(area_up_id);
            if (area != null) infos.Add(area);
            else infos.Add(null);
            area = user.getAreaById(area_down_id);
            if (area != null) infos.Add(area);
            else infos.Add(null);
            if (area_left_id > 0)
            {
                area = user.getAreaById(area_left_id);
                if (area != null) infos.Add(area);
                else infos.Add(null);
            }
            else infos.Add(null);
            if (area_right_id > 0)
            {
                area = user.getAreaById(area_right_id);
                if (area != null) infos.Add(area);
                else infos.Add(null);
            }
            else infos.Add(null);
            return infos;
        }
        /// <summary>
        /// returns, 0=success, 1=http failure, 2=city hp recovering, 3=unknown
        /// </summary>
        /// <param name="areaId"></param>
        /// <returns></returns>
        public int moveToArea(ProtocolMgr protocol, ILogger logger, User user, int areaId)
        {
            string url = "/root/world!transferInNewArea.action";
            string data = "areaId=" + areaId;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "新世界移动城市");
            if (result == null) return 1;
            if (!result.CmdSucceed)
            {
                if (result.CmdError.IndexOf("城防自动恢复完毕") >= 0) return 2;
                else return 3;
            }
            XmlDocument xml = result.CmdResult;
            AreaInfo area = user.getAreaById(areaId);
            if (area != null)
            {
                user._attack_selfCityId = area.areaid;
                logInfo(logger, String.Format("移动到城市[{0}]", area.areaname));
                return 0;
            }
            return 3;
        }
        #endregion

        #region attack player
        public long find_and_attack(ProtocolMgr protocol, ILogger logger, User user, int _reserve_token, bool _attack_only_not_injail,
            bool _attack_npc, int _level_min, int _level_max)
        {
            int self_nation = user.NationInt;
            List<AreaInfo> near_areas = getNearAreas(user);
            bool if_any_can_attack = false, if_attacked = false;
            int min_protect_cd = 0;
            if (user.AttackOrders <= _reserve_token) return next_hour();
            int result = ServiceFactory.getTroopManager().makeSureForce(protocol, logger);
            if (result != 0)
            {
                logInfo(logger, "征兵失败, 暂停攻击玩家1分钟");
                return 60 * 1000;
            }
            foreach (AreaInfo info in near_areas)
            {
                if (user.AttackOrders <= _reserve_token) return next_hour();
                if (info == null || info.scopecount == 0) continue;
                for (int i = 1, len = info.scopecount; i <= len; i++)
                {
                    if (user.AttackOrders <= _reserve_token) return next_hour();
                    List<ScopeCity> citys = getAreaScopeInfo(protocol, logger, user, info.areaid, i);
                    if (citys == null) break;
                    if (citys.Count == 0) break;
                    foreach (ScopeCity city in citys)
                    {
                        if (user.AttackOrders <= _reserve_token) return next_hour();
                        if (_attack_only_not_injail && city.arreststate == 1) continue;
                        if (city.nation != self_nation && city.protectcd == 0)
                        {
                            // 判断是否符合用户设置的要求, 级别限制和Npc限制
                            if (city.playerid < 0)
                            {
                                if (!_attack_npc) continue; // 设置npc不打, 那么略过npc
                            }
                            else if (city.citylevel > _level_max || city.citylevel < _level_min)
                            {
                                continue;
                            }
                            if_any_can_attack = true;
                            int attack_result = attackPlayer(protocol, logger, user, info.areaid, i, city.cityid);
                            if (attack_result == 0)
                            {
                                if_attacked = true;
                            }
                            else if (attack_result == 2) // token cd
                            {
                                return user.TokenCdTime;
                            }
                            else if (attack_result == 3) // in jail
                            {
                                escapeFromJail(protocol, logger);
                                return 60 * 1000;
                            }
                            else if (attack_result == 4) // cannot reach
                            {
                                if (user._attack_cityHpRecoverCd > 0) return user._attack_cityHpRecoverCd;
                                else return next_halfhour();
                            }
                            else if (attack_result == 5) // not enough orders
                            {
                                return next_hour();
                            }
                            else if (attack_result == 6) // in team
                            {
                                return 2 * 60 * 1000;
                            }
                            break;
                        }
                        else if (city.nation != self_nation)
                        {
                            if (min_protect_cd == 0) min_protect_cd = city.protectcd;
                            else if (city.protectcd < min_protect_cd) min_protect_cd = city.protectcd;
                        }
                    }
                }
            }
            // 如果一个人没打到, 那么继续向前走, 如果向前走不动, 那么退回去, 等保护cd和攻击cd完了再过来打
            if (if_attacked) return immediate();
            else if (if_any_can_attack) return min_protect_cd;
            else return -1; // 没有人可打, 那么告诉函数外, 没人可打
        }
        public List<ScopeCity> getAreaScopeInfo(ProtocolMgr protocol, ILogger logger, User user, int areaId, int scopeId)
        {
            AreaInfo area = user.getAreaById(areaId);
            if (area == null) return null;
            List<ScopeCity> citys = new List<ScopeCity>();
            string url = "/root/area!getAllCity.action";
            string data = String.Format("areaId={0}&scopeId={1}", areaId, scopeId);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data,
                String.Format("新世界查看城市[{0}(区域数量{1}), 查看区域{2}]", area.areaname, area.scopecount, scopeId));
            if (result == null) return citys;
            if (!result.CmdSucceed) return null;
            XmlDocument xml = result.CmdResult;
            XmlNodeList scope_nodes = xml.SelectNodes("/results/city");

            foreach (XmlNode scope_node in scope_nodes)
            {
                XmlNodeList child_nodes = scope_node.ChildNodes;
                ScopeCity city = new ScopeCity();
                foreach (XmlNode child in child_nodes)
                {
                    if (child.Name == "cityid") city.cityid = Int32.Parse(child.InnerText);
                    else if (child.Name == "scopeid") city.scopeid = Int32.Parse(child.InnerText);
                    else if (child.Name == "playerid") city.playerid = Int32.Parse(child.InnerText);
                    else if (child.Name == "citytype") city.citytype = Int32.Parse(child.InnerText);
                    else if (child.Name == "arreststate") city.arreststate = Int32.Parse(child.InnerText);
                    else if (child.Name == "nation") city.nation = Int32.Parse(child.InnerText);
                    else if (child.Name == "citylevel") city.citylevel = Int32.Parse(child.InnerText);
                    else if (child.Name == "protectcd") city.protectcd = Int32.Parse(child.InnerText);
                }
                citys.Add(city);
            }
            return citys;
        }
        /// <summary>
        /// attack players, results: 0=success, 1=http failure, 2=cd, 3=in jail, 4=cannot reach, 5=not enough orders, 6=other
        /// </summary>
        /// <param name="areaId">area id</param>
        /// <param name="scopeId">scope id</param>
        /// <param name="cityId">city id</param>
        /// <returns>0=success, 1=http failure, 2=cd, 3=in jail, 4=cannot reach, 5=not enough orders, 6=in team 7other</returns>
        private int attackPlayer(ProtocolMgr protocol, ILogger logger, User user, int areaId, int scopeId, int cityId)
        {
            string url = "/root/world!attackOtherAreaCity.action";
            string data = String.Format("areaId={0}&scopeId={1}&cityId={2}", areaId, scopeId, cityId);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "攻击玩家");
            if (result == null) return 1;
            if (!result.CmdSucceed)
            {
                if (result.CmdError.IndexOf("军令还没有冷却") >= 0) return 2;
                else if (result.CmdError.IndexOf("请先逃跑") >= 0) return 3;
                else if (result.CmdError.IndexOf("距离太远") >= 0) return 4;
                else if (result.CmdError.IndexOf("没有足够的攻击令") >= 0) return 5;
                else if (result.CmdError.IndexOf("组队") >= 0) return 6;
                else return 7;
            }
            XmlDocument xml = result.CmdResult;
            XmlNode report_node = xml.SelectSingleNode("/results/battlereport");
            int attack_hpchange = 0, defend_hpchange = 0, attack_score = 0;
            if (report_node == null) // means attacked npc
            {
                XmlNode attack_hpchange_node = xml.SelectSingleNode("/results/attcityhpchange");
                if (attack_hpchange_node != null) Int32.TryParse(attack_hpchange_node.InnerText, out attack_hpchange);
                XmlNode defend_hpchange_node = xml.SelectSingleNode("/results/defcityhpchange");
                if (defend_hpchange_node != null) Int32.TryParse(defend_hpchange_node.InnerText, out defend_hpchange);
                XmlNode attack_score_node = xml.SelectSingleNode("/results/attscore");
                if (attack_score_node != null) Int32.TryParse(attack_score_node.InnerText, out attack_score);

                string desc = String.Format("攻打城市守备军, 您城防减少{0}, 守备军城防减少{1}, 您获得战绩{2}", attack_hpchange, defend_hpchange, attack_score);
                logInfo(logger, desc);
            }
            else // means attacked player
            {
                int attack_lost = 0, defend_lost = 0, attack_level = 0, defend_level = 0; string message = "", report_url = "";
                XmlNode attack_hpchange_node = xml.SelectSingleNode("/results/battlereport/attcityhpchange");
                if (attack_hpchange_node != null) Int32.TryParse(attack_hpchange_node.InnerText, out attack_hpchange);
                XmlNode defend_hpchange_node = xml.SelectSingleNode("/results/battlereport/defcityhpchange");
                if (defend_hpchange_node != null) Int32.TryParse(defend_hpchange_node.InnerText, out defend_hpchange);
                XmlNode attack_score_node = xml.SelectSingleNode("/results/battlereport/attscore");
                if (attack_score_node != null) Int32.TryParse(attack_score_node.InnerText, out attack_score);

                XmlNode attack_level_node = xml.SelectSingleNode("/results/attacker/playerlevel");
                if (attack_level_node != null) Int32.TryParse(attack_level_node.InnerText, out attack_level);
                XmlNode defend_level_node = xml.SelectSingleNode("/results/defender/playerlevel");
                if (defend_level_node != null) Int32.TryParse(defend_level_node.InnerText, out defend_level);
                XmlNode attack_lost_node = xml.SelectSingleNode("/results/battlereport/attlost");
                if (attack_lost_node != null) Int32.TryParse(attack_lost_node.InnerText, out attack_lost);
                XmlNode defend_lost_node = xml.SelectSingleNode("/results/battlereport/deflost");
                if (defend_lost_node != null) Int32.TryParse(defend_lost_node.InnerText, out defend_lost);
                XmlNode message_node = xml.SelectSingleNode("/results/battlereport/message");
                if (message_node != null) message = message_node.InnerText;

                XmlNode report_url_node = xml.SelectSingleNode("/results/reporturl");
                if (report_url_node != null) report_url = report_url_node.InnerText;

                string slave_name = "";
                XmlNode slave_node = xml.SelectSingleNode("/results/slavename");
                if (slave_node != null) slave_name = slave_node.InnerText;

                string desc = String.Format("{0}{1} 获得战绩{2}, 您/敌({3}级)城防减少{4}/{5}, 战报地址: {6}",
                    message, slave_name, attack_score, defend_level, attack_hpchange, defend_hpchange, report_url);
                logInfo(logger, desc);
            }
            return 0;
        }
        #endregion

        #region  jail info
        public void doJail(ProtocolMgr protocol, ILogger logger, User user, bool _do_jail_tech, int gold_available)
        {
            if (!user._attack_have_jail) return;
            List<int> slave_ids = getJailInfo(protocol, logger, user, _do_jail_tech, gold_available);
            if (!user._attack_have_jail) return;
            if (slave_ids == null) return;
            if (slave_ids.Count > 0)
            {
                foreach (int slave_id in slave_ids)
                {
                    slashJailWorker(protocol, logger, slave_id);
                }
            }
        }
        private bool escapeFromJail(ProtocolMgr protocol, ILogger logger)
        {
            string url = "/root/jail!escape.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "从监狱逃跑");
            if (result == null || !result.CmdSucceed) return false;
            logInfo(logger, "从监狱逃跑, 1分钟后成功");
            return true;
        }
        public List<int> getJailInfo(ProtocolMgr protocol, ILogger logger, User user, bool _do_jail_tech, int gold_available)
        {
            List<int> slave_ids = new List<int>();
            string url = "/root/jail.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取监狱信息");
            if (result == null) return null;
            if (!result.CmdSucceed)
            {
                user._attack_have_jail = false;
                return null;
            }
            user._attack_have_jail = true;
            XmlDocument xml = result.CmdResult;
            XmlNodeList prisoner_nodes = xml.SelectNodes("/results/prisoner");
            foreach (XmlNode prisoner_node in prisoner_nodes)
            {
                int slave_id = 0; bool slashed = false;
                XmlNodeList child_nodes = prisoner_node.ChildNodes;
                foreach (XmlNode child in child_nodes)
                {
                    if (child.Name == "slaveid") slave_id = Int32.Parse(child.InnerText);
                    else if (child.Name == "slashstate") slashed = child.InnerText != "1";
                }
                if (!slashed) slave_ids.Add(slave_id);
            }
            slashFreeWorker(protocol, logger, xml);

            if (_do_jail_tech)
            {
                int upgrade_gold = 20;
                XmlNode upgrade_gold_node = xml.SelectSingleNode("/results/pergold");
                if (upgrade_gold_node != null) Int32.TryParse(upgrade_gold_node.InnerText, out upgrade_gold);
                if (upgrade_gold <= gold_available)
                {
                    XmlNode remain_time_node = xml.SelectSingleNode("/results/remaintime");
                    if (remain_time_node == null) // 不存在这个字段, 说明今天还没有进行研究
                    {
                        doJailTech(protocol, logger, upgrade_gold);
                    }
                }
            }

            return slave_ids;
        }
        public void doJailTech(ProtocolMgr protocol, ILogger logger, int gold_need)
        {
            string url = "/root/jail!techResearch.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "典狱技术研究");
            if (result == null || !result.CmdSucceed) return;
            logInfo(logger, "典狱劳作技术研究成功, 花费金币" + gold_need);
            XmlDocument xml = result.CmdResult;
            slashFreeWorker(protocol, logger, xml);
        }
        public void slashFreeWorker(ProtocolMgr protocol, ILogger logger, XmlDocument xml)
        {
            if (xml == null) return;
            int count = 0;
            XmlNode free_worker_node = xml.SelectSingleNode("/results/freeprisoner");
            if (free_worker_node != null) Int32.TryParse(free_worker_node.InnerText, out count);
            if (count == 0) return;
            for (int i = 0; i < count; i++)
            {
                slashJailWorker(protocol, logger, 0);
            }
        }
        public void slashJailWorker(ProtocolMgr protocol, ILogger logger, int slaveId)
        {
            string url = "/root/jail!slash.action";
            string data;
            if (slaveId != 0) data = "slaveId=" + slaveId;
            else data = "slaveId=Free";
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "监狱训诫");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results><state>1</state><baoshi>8</baoshi></results>
            XmlNode gem_node = xml.SelectSingleNode("/results/baoshi");
            if (gem_node != null)
            {
                int gem_number = 0;
                Int32.TryParse(gem_node.InnerText, out gem_number);
                if (gem_number > 0)
                {
                    logInfo(logger, String.Format("典狱训诫成功, 获得宝石{0}个", gem_number));
                }
            }
        }
        #endregion

        #region extra order
        /// <summary>
        /// 获取马车信息
        /// </summary>
        public void handleTransferInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/world!getTranferInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取马车信息");
            if (result == null) return;
            if (!result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results>
            //  <state>1</state>
            //  <canget>1</canget>
            //  <tranfercdcost>3000</tranfercdcost>
            //  <tranfereffect>14</tranfereffect>
            //  <nexttranfereffect>30</nexttranfereffect>
            //  <token>14</token>
            //  <tranferlevel>3</tranferlevel>
            //</results>
            bool _can_get_attack_order = false; int _can_get_attack_order_num = 0;
            XmlNode canget_node = xml.SelectSingleNode("/results/canget");
            if (canget_node != null) _can_get_attack_order = canget_node.InnerText.Equals("1");

            XmlNode token_node = xml.SelectSingleNode("/results/token");
            if (token_node != null) Int32.TryParse(token_node.InnerText, out _can_get_attack_order_num);

            if (!_can_get_attack_order) return;
            // get extra order
            url = "/root/world!getTransferToken.action";
            result = protocol.getXml(url, "获取个人攻击令");
            if (result == null) return;
            if (!result.CmdSucceed) return;
            xml = result.CmdResult;
            logInfo(logger, String.Format("获取个人攻击令成功, 攻击令+{0}", _can_get_attack_order_num));
        }
        #endregion

        #region gong jian zhan
        /// <summary>
        /// 获取攻坚战信息
        /// </summary>
        public void getNationBattleInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/nation!getNationTaskNewInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取攻坚战信息");
            if (result == null) return;
            if (!result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results>
            //  <state>1</state>
            //  <year>293</year>
            //  <season>3</season>
            //  <status>0</status>
            //  <nexttime>8780703</nexttime>
            //</results>
            //<results>
            //  <state>1</state>
            //  <year>353</year>
            //  <season>2</season>
            //  <status>1</status>
            //  <masscity>赤壁</masscity>
            //  <pic>1</pic>
            //  <massnum>50</massnum>
            //  <remaintime>1715085</remaintime>
            //  <citynation>1</citynation>
            //  <donenum>8</donenum>
            //</results>
            //<results>
            //  <state>1</state>
            //  <year>353</year>
            //  <season>2</season>
            //  <status>2</status>
            //  <boxjoin>5</boxjoin>
            //  <boxmass>0</boxmass>
            //  <boxtask>2</boxtask>
            //  <remaintime>2814167</remaintime>
            //  <task>
            //    <name>抓获劳工</name>
            //    <finishgoal>0</finishgoal>
            //    <goal>3</goal>
            //    <goallist>50,100,150</goallist>
            //    <num>38</num>
            //    <content>全国抓获50,100,150劳工</content>
            //  </task>
            //  <task>
            //    <name>擒贼擒王</name>
            //    <finishgoal>1</finishgoal>
            //    <goal>1</goal>
            //    <goallist>50</goallist>
            //    <num>50</num>
            //    <content>击败敌国国家公敌50次</content>
            //  </task>
            //  <task>
            //    <name>攻坚破防</name>
            //    <finishgoal>1</finishgoal>
            //    <goal>1</goal>
            //    <goallist>1500</goallist>
            //    <num>1500</num>
            //    <content>摧毁敌国1500城防</content>
            //  </task>
            //</results>
            //<results>
            //  <state>1</state>
            //  <year>353</year>
            //  <season>2</season>
            //  <status>3</status>
            //  <box>9</box>
            //</results>
            XmlNode nexttime_node = xml.SelectSingleNode("/results/nexttime");
            if (nexttime_node != null) Int64.TryParse(nexttime_node.InnerText, out user._attack_nationBattleCd);
            else user._attack_nationBattleCd = 0;

            XmlNode status_node = xml.SelectSingleNode("/results/status");
            if (status_node != null) Int32.TryParse(status_node.InnerText, out user._attack_gongjian_status);
            else user._attack_gongjian_status = -1;

            XmlNode remaintime_node = xml.SelectSingleNode("/results/remaintime");
            if (remaintime_node != null) Int64.TryParse(remaintime_node.InnerText, out user._attack_nationBattleRemainTime);
            else user._attack_nationBattleRemainTime = 0;

            XmlNode city_node = xml.SelectSingleNode("/results/masscity");
            if (city_node != null) user._attack_nation_battle_city = city_node.InnerText;
            else user._attack_nation_battle_city = "";
        }
        /// <summary>
        /// 获取攻坚战奖励
        /// </summary>
        public void getNationBattleReward(ProtocolMgr protocol, ILogger logger)
        {
            string url = "/root/nation!getNationTaskNewReward.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取攻坚战奖励");
            if (result == null) return;
            if (!result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results>
            //  <state>1</state>
            //  <box>9</box>
            //  <allbox>425</allbox>
            //</results>
            XmlNode box_node = xml.SelectSingleNode("/results/box");
            if (box_node != null) logInfo(logger, String.Format("获取攻坚战奖励, 国家宝箱+{0}", box_node.InnerText));
        }
        /// <summary>
        /// 获取国家攻击/防御令城市信息
        /// </summary>
        private void getWorldTokenInfo(ProtocolMgr protocol, ILogger logger)
        {
            string url = "/root/world!getNewAreaNationToken.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取国家攻击/防御令城市信息");
            if (result == null) return;
            if (!result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            //<results>
            //  <state>1</state>
            //  <nationtoken>
            //      <id>1</id>
            //      <nation>2</nation>
            //      <areaid>116</areaid>
            //      <areaname>华容</areaname>
            //      <active>1</active>
            //      <cd>0</cd>
            //  </nationtoken>
            //  <nationtoken>
            //      <id>2</id>
            //      <nation>2</nation>
            //      <areaid>105</areaid>
            //      <areaname></areaname>
            //      <active>0</active>
            //      <cd>0</cd>
            //  </nationtoken>
            //</results>
        }
        #endregion

        #region city event
        public bool acceptCityEvent(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/world!acceptCityEvent.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界接受城池事件");
            if (result == null || !result.CmdSucceed) return false;
            XmlDocument xml = result.CmdResult;
            //<results><state>1</state><cd>1200000</cd></results>
            int cdtime = 0;
            XmlNode cd_node = xml.SelectSingleNode("/results/cd");
            if (cd_node != null) Int32.TryParse(cd_node.InnerText, out cdtime);
            user._attack_current_cityevent_cdtime = cdtime;
            cdtime = cdtime / (60 * 1000);
            logInfo(logger, String.Format("接受城池事件[{0}], 将要执行时间为[{1}]分钟", user._attack_current_cityevent_name, cdtime));
            return true;
        }
        public bool cancelCityEvent(ProtocolMgr protocol, ILogger logger)
        {
            string url = "/root/world!cancelCityEvent.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界取消城池事件");
            if (result == null || !result.CmdSucceed) return false;
            XmlDocument xml = result.CmdResult;
            logInfo(logger, "取消城池事件");
            return true;
        }
        public bool getCityEventAward(ProtocolMgr protocol, ILogger logger)
        {
            string url = "/root/world!getCityEventReward.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "新世界拿取城池事件奖励");
            if (result == null || !result.CmdSucceed) return false;
            XmlDocument xml = result.CmdResult;
            //<results><state>1</state><reward><baoshi>40</baoshi></reward></results>
            XmlNode reward_node = xml.SelectSingleNode("/results/reward/baoshi");
            if (reward_node != null)
            {
                logInfo(logger, String.Format("新世界拿取城池事件奖励, 宝石+{0}", reward_node.InnerText));
            }
            return true;
        }
        #endregion

        #endregion

        #region resource campaign
        /// <summary>
        /// 0=success, 1=httpfailure, 2=cannot find res campaign, 3=no free tokens, 4=cannot complete, 10=other
        /// </summary>
        /// <param name="protocol"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        public int handleResCampaign(ProtocolMgr protocol, ILogger logger, int target_campaign_id=1)
        {
            int _freeTokenNumber = 0;
            List<ResCampaign> _campaigns = new List<ResCampaign>();

            string url = "/root/resCampaign!getResCamList.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取资源副本信息");
            if (result == null) return 1;
            if (!result.CmdSucceed) return 10;
            XmlDocument xml = result.CmdResult;
            XmlNode remain_node = xml.SelectSingleNode("/results/resetnum");
            if (remain_node != null) Int32.TryParse(remain_node.InnerText, out _freeTokenNumber);

            XmlNodeList cam_nodes = xml.SelectNodes("/results/cam");
            foreach (XmlNode cam_node in cam_nodes)
            {
                if (cam_node == null || !cam_node.HasChildNodes) continue;
                XmlNodeList childs = cam_node.ChildNodes;
                ResCampaign cam = new ResCampaign();
                foreach (XmlNode child in childs)
                {
                    if (child.Name == "id") cam.id = Int32.Parse(child.InnerText);
                    else if (child.Name == "name") cam.name = child.InnerText;
                    else if (child.Name == "armies") cam.armies = child.InnerText;
                    else if (child.Name == "status") cam.status = Int32.Parse(child.InnerText);
                    else if (child.Name == "reward") cam.reward = child.InnerText;
                    else if (child.Name == "finishreward") cam.finishreward = child.InnerText;
                }
                _campaigns.Add(cam);
            }

            // first find if any campaign is unfinished, 
            // if so, first finish it, ( if cannot defeat npc, ignore)
            // find if any free token, if any, use free token, and then finish specified campaign
            ResCampaign _cam = null;
            foreach (ResCampaign tmpcam in _campaigns)
            {
                if (tmpcam.id == target_campaign_id)
                {
                    _cam = tmpcam; break;
                }
            }
            if (_cam == null) return 2;
            if (_cam.status == 2 && _freeTokenNumber == 0) return 3;
            if (_cam.status == 1) // 1=not finished, 2=finished
            {
                string armies = _cam.armies;
                int first_undefeat_armyindex = -1;
                for (int i = 0; i < armies.Length; i++)
                {
                    //1=defeated, 0=undefeated
                    if (armies[i].Equals('0'))
                    {
                        first_undefeat_armyindex = i;
                        break;
                    }
                }
                while(first_undefeat_armyindex >= 0 && first_undefeat_armyindex < 5)
                {
                    int attack_result = attackCampaignNpc(protocol, logger, _cam, first_undefeat_armyindex);
                    if (attack_result == 1) return 1;
                    if (attack_result == 2) return 2;
                    if (attack_result == 3) return 4;
                    first_undefeat_armyindex++;
                }
            }
            else if (_freeTokenNumber > 0)
            {
                int free_result = useFreeTokenReleaseCampaign(protocol, logger, _cam, ref _freeTokenNumber);
                int first_undefeat_armyindex = 0;
                while (first_undefeat_armyindex < 5)
                {
                    int attack_result = attackCampaignNpc(protocol, logger, _cam, first_undefeat_armyindex);
                    if (attack_result == 1) return 1;
                    if (attack_result == 2) return 2;
                    if (attack_result == 3) return 4;
                    first_undefeat_armyindex++;
                }
            }

            return 0;
        }
        /// <summary>
        /// returns 0=success, 1=http fail, 2=command error
        /// </summary>
        /// <param name="campaignId"></param>
        /// <returns></returns>
        private int useFreeTokenReleaseCampaign(ProtocolMgr protocol, ILogger logger, ResCampaign campaign, ref int _freeTokenNumber)
        {
            string url = "/root/resCampaign!resetResCamNum.action";
            string data = "id=" + campaign.id;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "使用副本重置卡");
            if (result == null) return 1;
            if (!result.CmdSucceed) return 2;
            //<results><state>1</state><message></message></results>
            logInfo(logger, String.Format("使用副本重置卡重置副本[{0}], 副本重置卡还剩[{1}]个", campaign.name, _freeTokenNumber - 1));
            return 0;
        }
        private void getCampaignInfo(ProtocolMgr protocol, ILogger logger, int campaignId)
        {
            string url = "/root/resCampaign!getInfo.action";
            string data = "id=" + campaignId;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "获取副本信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
        }
        /// <summary>
        /// returns, 0=sucess, 1=http fail, 2=attack error, 3=not defeat npc
        /// </summary>
        /// <param name="campaignId"></param>
        /// <param name="npcIndex"></param>
        /// <returns></returns>
        private int attackCampaignNpc(ProtocolMgr protocol, ILogger logger, ResCampaign campaign, int npcIndex)
        {
            string url = "/root/resCampaign!attack.action";
            string data = String.Format("armyIndex={0}&id={1}", npcIndex, campaign.id);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "攻击副本NPC");
            if (result == null) return 1;
            if (!result.CmdSucceed) return 2;
            XmlDocument xml = result.CmdResult;

            string desc = "攻击副本NPC, ";
            XmlNode message_node = xml.SelectSingleNode("/results/battlereport/message");
            if (message_node != null) desc += message_node.InnerText;

            bool defeat_npc = false;
            XmlNode winside_node = xml.SelectSingleNode("/results/battlereport/winside");
            if (winside_node != null) defeat_npc = winside_node.InnerText == "1";

            if (defeat_npc)
            {
                desc += " 您获得了 " + campaign.getRewardByNpcIndex(npcIndex);
                logInfo(logger, desc);
                return 0;
            }
            else
            {
                logInfo(logger, desc);
                return 3;
            }
        }
        private class ResCampaign
        {
            //<cam>
            //    <id>6</id>
            //    <name>乌江自刎</name>
            //    <pic>38</pic>
            //    <finishnum>0</finishnum>
            //    <armies>00000</armies>
            //    <status>0=还不能打, 1=第一次还未打, 2=已打完, </status>
            //    <gold>78</gold>
            //    <reward>res:copper:700000;res:copper:700000;res:copper:700000;res:copper:700000;res:copper:700000</reward>
            //    <finishreward>res:copper:500000</finishreward>
            //</cam>
            public int id;
            public string name;
            public string armies;
            public int status;
            public string reward;
            public string finishreward;
            public string getRewardByNpcIndex(int npcIndex)
            {
                string result = "";
                string[] rewards = reward.Split(';');
                if (rewards.Length < npcIndex) return "";
                result += generateReward(rewards[npcIndex]);
                if (npcIndex == 4)
                {
                    result += "; 完成副本奖励: " + generateReward(finishreward);
                }
                return result;
            }
            private string generateReward(string rewardString)
            {
                if (rewardString == null || rewardString == "") return "";
                string[] rewards = rewardString.Split(':');
                if (rewards.Length < 3) return "";
                string type = rewards[1], num = rewards[2];
                string translate_type = "";
                if (type == "copper")
                {
                    translate_type = "银币";
                }
                else if (type == "baoshi")
                {
                    translate_type = "宝石";
                    if (rewards.Length >= 4) num = rewards[3];
                    else num = "<<未知的错误>>";
                }

                return String.Format("{0}+{1}", translate_type, num);
            }
        }
        #endregion
    }
}
